package service

import (
	"context"
	"fmt"
	"github.com/minio/minio-go/v7"
	"github.com/minio/minio-go/v7/pkg/credentials"
	"io"
	"log"
)

// StorageClient 定义了与存储系统（如 MinIO）交互的方法。
type StorageClient interface {
	// UploadFile 上传文件到存储
	UploadFile(ctx context.Context, bucketName, objectName string, file io.Reader) (string, error)

	// GetFile 下载文件
	GetFile(ctx context.Context, bucketName, objectName string) (io.Reader, error)

	// DeleteFile 删除文件
	DeleteFile(ctx context.Context, bucketName, objectName string) error
}

// MinioClient 实现了 StorageClient 接口
type MinioClient struct {
	client  *minio.Client
	baseURL string
}

// NewMinioClient 构造 MinioClient 实例
func NewMinioClient(endpoint, accessKeyID, secretAccessKey string, useSSL bool) (*MinioClient, error) {
	client, err := minio.New(endpoint, &minio.Options{
		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
		Secure: useSSL,
	})
	if err != nil {
		log.Fatalf("Unable to initialize MinIO client: %v", err)
		return nil, err
	}
	return &MinioClient{client: client, baseURL: fmt.Sprintf(`http://%v:9000:`, endpoint)}, nil
}

// UploadFile 实现 StorageClient 接口中的 UploadFile 方法
func (m *MinioClient) UploadFile(ctx context.Context, bucketName, objectName string, file io.Reader) (string, error) {
	_, err := m.client.PutObject(ctx, bucketName, objectName, file, -1, minio.PutObjectOptions{})
	if err != nil {
		log.Printf("Error uploading file: %v", err)
		return "", err
	}
	// 构建文件的 URL 地址
	fileURL := fmt.Sprintf("%s/%s/%s", m.baseURL, bucketName, objectName)
	return fileURL, nil
}

// GetFile 实现 StorageClient 接口中的 GetFile 方法
func (m *MinioClient) GetFile(ctx context.Context, bucketName, objectName string) (io.Reader, error) {
	object, err := m.client.GetObject(ctx, bucketName, objectName, minio.GetObjectOptions{})
	if err != nil {
		return nil, err
	}
	return object, nil
}

// DeleteFile 实现 StorageClient 接口中的 DeleteFile 方法
func (m *MinioClient) DeleteFile(ctx context.Context, bucketName, objectName string) error {
	err := m.client.RemoveObject(ctx, bucketName, objectName, minio.RemoveObjectOptions{})
	return err
}
